package kernel.process;

import java.io.File;
import java.util.List;

import kernel.FileManager;
import kernel.IOManager;
import kernel.exception.OSException;

/**
 * Abstract process definition completely with needed methods
 * @author Jaromir Lepic, Petr Hajek, Veronika Vencurikova
 *
 */
public abstract class AbstractProcess extends AbstractProcessHeader{
	protected Thread dispatcher;
	protected long pid;
	protected volatile boolean alive = false;
	protected volatile boolean shouldEnd = false;
	public static final String HELP = "-h";
	public static final String HELP2 = "--help";
	
	/**
	 * Creates new abstract of a process
	 * @param name Process name
	 * @param params Parameters of process
	 * @param input Input redirection
	 * @param output Output redirection
	 * @param append Append to output
	 * @param shellID ID of shell where messages are send
	 * @param userID User of the process
	 * @param pid Process ID
	 */
	public AbstractProcess(String name, List<String> params, String input,
			String output, boolean append, long shellID, String userID, long pid) {
		super(name, params, input, output, append, shellID, userID);
		this.setPid(pid);
	}
	
	/**
	 * Creates new abstract of a process from a header
	 * @param header
	 * @param pid Process ID
	 */
	public AbstractProcess(AbstractProcessHeader header, long pid){
		super(header.getName(), header.getParams(), header.getInput(), header.getOutput(), header.getAppend(), header.getShellID(), header.getUserID());
		this.setPid(pid);
	}
	
	/**
	 * Sets the dispatcher and calls main doJob(input)
	 * @param input Input to be processed
	 * @param dispatcher Thread dispatching this process
	 * @return Output of the job
	 * @throws OSException
	 */
	public final String doJob(String input, Thread dispatcher) throws OSException{
		this.dispatcher = dispatcher;
		return doJob(input);
	}
	
	/**
	 * Tells if the process is still alice
	 * @return True if alice
	 */
	public boolean isAlive(){
		return this.alive;
	}
	
	/**
	 * Method to do repeated tasks of a process.
	 * Set shouldEnd to true inside if not used.
	 * @return Output of the job
	 * @throws OSException
	 */
	public abstract String continueJob() throws OSException;
	
	/**
	 * Call to finish the job a set appropriate variables
	 * @return
	 * @throws OSException
	 */
	public final String finishJob() throws OSException{
		String out = finalizeJob();
		this.alive = false;
		return out;
	}
	
	/**
	 * Method to do last tasks in a process
	 * @return Output of the job
	 * @throws OSException
	 */
	protected abstract String finalizeJob() throws OSException;
	
	/**
	 * Call to terminate process
	 * @throws OSException
	 */
	public final void killProcess() throws OSException {
		this.shouldEnd = true;
		if (this.dispatcher != null)
			this.dispatcher.interrupt();
		kill();
	}
	
	/**
	 * Tests if the process should end
	 * @return True if should end
	 */
	public boolean shouldEnd(){
		return this.shouldEnd;
	}
		
	/**
	 * The main job of the process
	 * @param input Input to be passed
	 * @return Output of the job
	 * @throws OSException
	 */
	protected abstract String doJob(String input) throws OSException;
	
	/**
	 * Returns true if parameters are needed and otherwise standard input is used
	 * @return true if needed
	 */
	public abstract boolean needParams(); 
	
	/**
	 * Call to terminate the process. Used when specific tasks need to be done before kill.
	 * @throws OSException
	 */
	protected abstract void kill() throws OSException;
	
	/**
	 * Returns canonical path of a file under working directory of a shell
	 * @param path Relative path to a file
	 * @param shellID shellID of target shell
	 * @return Canonical path to file
	 * @throws OSException
	 */
	public File absPath(String path, long shellID) throws OSException {
		return FileManager.getPath(path, getWd(shellID));
	}
	
	/**
	 * Gets working directory of a shell with given ID
	 * @param shellID ID of target shell
	 * @return Working directory of target shell
	 */
	public File getWd(long shellID) {
		return IOManager.getInstance().getWorkingDirectory(shellID);
	}
	
	/**
	 * Returns process ID 
	 * @return process ID
	 */
	public long getPid() {
		return pid;
	}

	/**
	 * Sets process ID
	 * @param pid New process ID
	 * @return instance of this process
	 */
	public AbstractProcess setPid(long pid) {
		this.pid = pid;
		return this;
	}
	
	/**
	 * Sets the dispather of this process
	 * @param dispatcher new dispatcher
	 * @return instance of this process
	 */
	public AbstractProcess setDispatcher (Thread dispatcher) {
		this.dispatcher = dispatcher;
		return this;
	}
	
	/**
	 * Prints the help text for this process
	 * @param command
	 * @return
	 */
	public abstract String man(String command);
}
